package _4_multithread._1_basic;

import lombok.extern.java.Log;
import org.junit.Test;

/* 1. 线程的创建
 *
 * 2. 线程的生命周期
 *
 * java.util.concurrent
 *
 */
@Log
public class _1_Basic {

    // main 方法是 VM 启动时的主线程
    public static void main(String[] args) {
    }

    static class ImplRunnable implements Runnable {
        // 实现run()方法
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("ImplRunnable thread: " + i);
            }
        }
    }

    static class ExtendThread extends Thread {
        //重写run()方法
        @Override
        public void run() {
            for (int i = 0; i <= 10; i++) {
                System.out.println("ExtendThread thread：" + i);
            }
        }
    }

    /**
     * 创建线程的两种方法：
     *     1. 实现 Runnable {@link Runnable} 接口
     *     2. 继承 Thread {@link Thread} 类，重写 run {@link Thread#run} 方法
     *
     * @see #simple()  简单的写法
     * 实现接口 用的更多
     */
    @Test
    public void createThreadImplRunnable() {
        //---------- 方法1: 实现 Runnable 接口 ----------
        ImplRunnable implRunnable = new ImplRunnable(); // new 了一个线程对象
        // implRunnable.run(); // 此处是方法调用，而不是新建了一个线程，还是在当前线程
        // 创建 新的线程
        Thread thread = new Thread(implRunnable);
        thread.start(); // 调用 start 方法，新线程执行 run() 方法
        // 这时，主线程 和 新建的线程会交替执行，即 并行执行

        for (int i = 0; i < 10; i++) {
            System.out.println("Main thread: " + i);
        }
    }

    @Test
    public void createThreadExtendThread() {
        //---------- 方法2: 继承 Thread 类 ----------
        ExtendThread extendThread = new ExtendThread();
        extendThread.start(); // 调用start()方法启动 新线程

        for (int i = 0; i < 10; i++) {
            System.out.println("Main thread: " + i);
        }
    }

    // 简单写法
    public void simple() {
        // 使用lambda表达式
        new Thread(() -> System.out.println("thread1 start ... ")).start();

        // 方法1 使用匿名内部类:
        new Thread() {
            public void run() {
                System.out.println("thread1 start ... ");
            }
        }.start();

        // 方法2 使用匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2 start .... ");
            }
        }).start();
    }




    /**
     * {@link Thread.State}
     */
    /* 线程的状态
     *
     * NEW:
     *    new Thread 之后，未启动时（未调用 start()方法 ）
     *
     * RUNNABLE:
     *    在JVM中运行中，可能等待系统进程
     *
     * BLOCKED:
     *    多线程竞争锁，当前线程等待其他线程释放锁，当前线程就是 Blocked
     *
     * WAITING:
     *    Object.wait 或 Thread.join 或 LockSupport.park 之后
     *    当前线程处于waiting，等待其他线程 执行特定操作
     *   例如：
     *    一线程 call wait() 等待其他线程 notify() 或 notifyAll()
     *    一线程 调用 join() 也处于waiting，等待 join的线程执行结束
     *
     * TIMED_WAITING:
     *     有时间限制的 waiting
     *      Object.wait with timeout
     *      Thread.join(long) with timeout
     *      LockSupport#parkNanos LockSupport.parkNanos
     *      LockSupport#parkUntil LockSupport.parkUntil
     *
     * TERMINATED
     *    线程的run方法已经执行完毕了, 基本上就等于死亡了
     *    (但是如果线程被持久持有, 可能不会被回收)
     */
    @Test
    public void threadState() {
        long time = System.currentTimeMillis();


        ImplRunnable runnable1 = new ImplRunnable();
        // new 状态
        Thread thread1 = new Thread(runnable1);
        log.info("" + thread1.getState());

        thread1.start();
        log.info("" + thread1.getState());

        // Blocked 需要多个线程竞争
        Thread thread2 = new Thread(runnable1);
        thread2.start();
        log.info("" + thread2.getState());
    }

    /**
     * 线程等待锁时的状态是? answer: BLOCKED
     */
    @Test
    public void testThreadLockState() throws Exception {
        Object lock = new Object();
        Thread t = new Thread(() -> {
            synchronized (lock) {
                log.info("thread t enter!");
            }
        });
        t.start();

        synchronized (lock) {
            log.info("thread main enter!");
            log.info("t state: " + t.getState());
        }
    }

}
